/**
 * EventServer 的文件驱动
 *
 * 使用方法：
 *
 * 对于使用派生类的用户，
 *   一、使用 event_file_driver_set_file 设置文件。
 *   二、若需创建新文件，使用 event_file_driver_create。注意，
 *       已有文件会被覆盖。
 *       event_file_driver_set_file_not_exist_throw 可以设置：
 *       true: 直接返回无文件错误，false: 将创建新文件。
 *   三、加载文件 event_file_driver_loader，此方法会调用派生类
 *       的 parser 钩子，将数据加载到派生类中。
 *   四、将数据序列化到文件使用 event_file_driver_dump，此方法
 *       会调用派生类的 writer 钩子，将派生类的数据写入文件中。
 *
 * 对于创建派生类的用户，
 *   一、初始化需要调用 EventFileDriver 的构造函数，析构时需要
 *       调用 EventFileDriver 的析构函数。
 *   二、在派生类添加或删除数据时，需要调用如下两个函数：
 *       1) event_file_driver_add_count_once    添加时调用
 *       2) event_file_driver_reduce_count_once 删除时调用
 *   三、需要实现下述的函数。
 *
 * EventFileDriver 的派生类需要实现两至三个函数：
 *   一、解析一个条目的方法
 *       int (*parser)(EventFileDriver *driver,
 *                     const epointer   data,
 *                     int              length)
 *       解析条目需要识别一段长度为 length 的自定义数据，并
 *       将其保存在自身结构中。返回值：0 成功，1 失败
 *
 *   二、反解析一个条目的方法
 *       EventFileDriverPack *(*writer)(EventFileDriver *driver)
 *       反解析需要把自身的条目结构变成可写入文件的二进制数据。
 *
 *       分别使用 event_file_driver_set_parser() 以及
 *       event_file_driver_set_writer() 来设置这两个方法
 *
 *   三、（可选）反解析前准备数据的方法
 *       int (*prepare_data)(EventFileDriver *driver)
 *       若反解析过数据，则数据表对象的迭代指针可能发生变化，由于
 *       EventDriverFile 父类不会操作子对象数据，所以需要子对象本身
 *       来提供重置迭代数据的方法。返回值：EVENT_FILE_DRIVER_SUCCESS,
 *       EVENT_FILE_DRIVER_PREPARE_DATA_ERROR
 */
#pragma once

#include "EventObject.h"
#include "EventRaw.h"

#include <libintl.h>

/* 一个数据表文件存储的最大条目数 */
#define EVENT_FILE_DRIVER_MAX_ITEMS_NUMBER 6000000
/* 数据表文件条目数起始字节 */
#define ITEMS_NUM_START 10
/* 数据表文件条目起始字节 */
#define ITEM_START (ITEMS_NUM_START + sizeof(int))

enum
{
	EVENT_FILE_DRIVER_SUCCESS		= 0,
	EVENT_FILE_DRIVER_NULL_OBJECT_ERROR	= 1,
	EVENT_FILE_DRIVER_NOT_HAVE_PARSER	= 2,
	EVENT_FILE_DRIVER_TABLE_LOADED_ERROR	= 3,
	EVENT_FILE_DRIVER_PATH_NOT_SET_ERROR	= 4,
	EVENT_FILE_DRIVER_FILE_OPEN_ERROR	= 5,
	EVENT_FILE_DRIVER_MAGIC_CHECK_ERROR	= 6,
	EVENT_FILE_DRIVER_FILE_IMCOMPLETE_ERROR = 7,
	EVENT_FILE_DRIVER_ITEM_SIZE_ERROR	= 8,
	EVENT_FILE_DRIVER_ITEMS_NUMBER_ERROR	= 9,
	EVENT_FILE_DRIVER_PARSER_DATA_ERROR	= 10,
	EVENT_FILE_DRIVER_WRITER_PACK_ERROR	= 11,
	EVENT_FILE_DRIVER_TABLE_NOT_LOAD_ERROR	= 12,
	EVENT_FILE_DRIVER_FILE_READ_ERROR	= 13,
	EVENT_FILE_DRIVER_PREPARE_DATA_ERROR	= 14,

	//
	EVENT_FILE_DRIVER_END,
};

/* 文件驱动报错文本 */
extern const char *event_file_driver_failed[EVENT_FILE_DRIVER_END];
#define EFD_FAILED(index) (gettext(event_file_driver_failed[index]))

/* 事件表文件驱动 */
typedef struct _EventFileDriver EventFileDriver;
/* 事件表文件驱动私有结构 */
typedef struct _EventFileDriverPriv EventFileDriverPriv;
/* 事件表数据包装类型 */
typedef struct _EventFileDriverPack EventFileDriverPack;

struct _EventFileDriver
{
	EventObject parent_instance;

	/* 私有数据 */
	EventFileDriverPriv *priv;
};

#define EVENT_FILE_DRIVER(any)	    ((EventFileDriver *)any)
#define EVENT_FILE_DRIVER_PACK(any) ((EventFileDriverPack *)any)

/* EventFileDriver 的构造函数 */
extern void event_file_driver_init(EventFileDriver *);
/* EventFileDriver 的析构函数 */
extern void event_file_driver_finalize(EventFileDriver *object);

/**
 * @brief 设置加载表对象时，若文件不存在，是否要直接返回错误。
 *        默认会直接抛出文件不存在错误，即 true。
 * @param will_throw : true: 直接返回无文件错误，false: 将创建新文件。
 */
extern void event_file_driver_set_file_not_exist_throw(EventFileDriver *self,
						       bool will_throw);

/**
 * 设置解析一个条目的方法
 * @param self : EventFileDriver
 * @param parser : 继承于 EventFileDriver 的数据解析方法
 */
extern void event_file_driver_set_parser(EventFileDriver *self,
					 int (*parser)(EventFileDriver *,
						       const epointer, int));

/**
 * 设置写入文件时的反解析数据方法
 * @param self : EventFileDriver
 * @param parser : 继承于 EventFileDriver 的数据反解析方法
 */
extern void
event_file_driver_set_writer(EventFileDriver	 *self,
			     EventFileDriverPack *(*writer)(EventFileDriver *),
			     int (*prepare_data)(EventFileDriver *));

/**
 * 设置 FileDriver 的文件路径
 * @param path : 数据表文件路径
 */
extern void event_file_driver_set_file(EventFileDriver *self, const char *path);

/**
 * 加载数据表
 * @param self : EventFileDriver 对象
 * @return : 返回枚举返回值，EVENT_FILE_DRIVER_NULL_OBJECT_ERROR，
 *           EVENT_FILE_DRIVER_FILE_OPEN_ERROR，
 *           EVENT_FILE_DRIVER_TABLE_LOADED_ERROR，
 *           EVENT_FILE_DRIVER_PATH_NOT_SET_ERROR，
 *           EVENT_FILE_DRIVER_NOT_HAVE_PARSER，
 *           EVENT_FILE_DRIVER_MAGIC_CHECK_ERROR，
 *           EVENT_FILE_DRIVER_FILE_IMCOMPLETE_ERROR，
 *           EVENT_FILE_DRIVER_ITEMS_NUMBER_ERROR，
 *           EVENT_FILE_DRIVER_ITEM_SIZE_ERROR，
 *           EVENT_FILE_DRIVER_PARSER_DATA_ERROR，
 *           EVENT_FILE_DRIVER_SUCCESS
 */
extern int event_file_driver_loader(EventFileDriver *self);

/**
 * 写入数据表
 * @param self : EventFileDriver 对象
 * @return : 返回枚举返回值，EVENT_FILE_DRIVER_NULL_OBJECT_ERROR，
 *           EVENT_FILE_DRIVER_TABLE_NOT_LOAD_ERROR，
 *           EVENT_FILE_DRIVER_WRITER_PACK_ERROR，
 *           EVENT_FILE_DRIVER_FILE_OPEN_ERROR，
 *           EVENT_FILE_DRIVER_SUCCESS
 */
extern int event_file_driver_dump(EventFileDriver *self);

/**
 * 创建空数据表，需要事先设置数据表文件路径。一般情况不需要使用！
 * 在 event_file_driver_loader 时就会创建不存在的文件。
 * @param self : EventFileDriver 对象
 * @return : 返回枚举返回值，EVENT_FILE_DRIVER_NULL_OBJECT_ERROR，
 *           EVENT_FILE_DRIVER_PATH_NOT_SET_ERROR，
 *           EVENT_FILE_DRIVER_FILE_OPEN_ERROR，
 *           EVENT_FILE_DRIVER_SUCCESS
 */
extern int event_file_driver_create(EventFileDriver *self);

/**
 * 增加一条数据条目数
 */
extern void event_file_driver_add_count_once(EventFileDriver *self);

/**
 * 减少一条数据条目数
 */
extern void event_file_driver_reduce_count_once(EventFileDriver *self);

/**
 * 创建一个 EventFileDriverPack
 * @param data : 绑定的数据，请注意，data 将交由 EventFileDriverPack
 *               管理，请勿释放该数据块。
 * @param length : 绑定的数据的大小。
 */
extern EventFileDriverPack *event_file_driver_pack_new(epointer data,
						       euint32	length);

/**
 * 从 EventRaw 对象创建一个 EventFileDriverPack
 * @param raw : EventRaw。请注意，raw 将交由 EventFileDriverPack 管理，
 *              请勿释放该数据块。
 */
extern EventFileDriverPack *event_file_driver_pack_new_from_raw(EventRaw *raw);

/**
 * 强制刷新条目数量。将逐步替换 add_count_once 和 reduce_count_once
 */
extern void event_file_driver_flush_items_num(EventFileDriver *self,
					      eint32	       items_num);
